<?php
/**
 +------------------------------------------------------------------------------
 * model for framework
 * model是底层数据库驱动的兼容层，直接调用数据库驱动
 +------------------------------------------------------------------------------
 * @version 1.9
 * @author  WangXian
 * @package ephp
 * @filename model.class.php
 * @creation date 2010-8-12
 * @modified date 2010-11-16 11:05:41
 +------------------------------------------------------------------------------
 */

class model
{
	private $table_name = '';
	private $field		= '*';
	private $orderby	= '';
	private $groupby 	= '';
	private $limit 		= '';
	private $where		= '';
	private $set_string	= '';
	
	private $query_sql		= '';		#用query($sql)方法，直接用SQL进行查询。
	private $db_change 		= false; 	#是否进行db切换
	public  $db_config_name = 'default';#默认的使用的数据库

	private $db=NULL;
	
	public function __construct()
	{}
	

	/** 连接数据库,只有在使用的时候才连接数据库，减少消耗。 **/
	protected function conn()
	{
		if(empty($this->db_config_name)) $this->db_config_name = 'default';

		// 这里判断是不是真的要连接数据库， 连接数据库有2种情况：
		// 1.之前没有数据库连接; 2.需要连接别的MySQL SERVER
		if(! is_object($this->db) || ($this->db_change == true))
		{
			$this->db = new db($this->db_config_name);
		}
		
		#这样可以直接在自定义model中使用$this->conn()->fetch_arrays()等，直接调用数据库驱动了，更灵活了
		return $this->db;
	}

	/**
	 * 调用数据库db::query方法，如果是SELECT可以后后续操作。
	 * @param  string $sql 要查询的SQL或执行commit的SQL等。
	 * @return mixed
	 */
	public function query($sql)
	{
		#鉴定是执行查询还是commit提交操作。如果是select，可以有后续操作。
		if(strtolower(substr($sql,0,6)) == 'select')
		{
			$this->query_sql = $sql;
			return $this;
		}
		else
		{
			$this->conn();
			return $this->db->query($sql);
		}
	}

	/**
	 * 生成SELECT类型的SQL语句
	 * @return string sql语句
	 */
	private function _read_sql()
	{
		//可能是query，直接接受SQL的查询操作
		if(empty($this->query_sql))
		{
			//$_field = $this->field;
			$_table_name = $this->_get_table_name();
	
			$_where = empty($this->where)?'':' WHERE '.$this->where;
			$_orderby = empty($this->orderby)?'':' ORDER BY '.$this->orderby;
			$_groupby = empty($this->groupby)?'':' GROUP BY '.$this->groupby;
			$_limit = empty($this->limit)?'':' LIMIT '.$this->limit;
	
			$sql = 'SELECT '. $this->field .' FROM '.$_table_name.$_where.$_groupby.$_orderby.$_limit;
			$this->db->sql = $sql;
			
			//清理使用过的变量
			$this->_clear_var();
			return $sql;
		}
		else
		{
			$this->db->sql = $this->query_sql;
			return $this->query_sql;
		}
	}
#------------------------------------------------------------------------------find相关操作

	/**
	 * 以array的方式返回查询结果
	 * @return array
	 */
	public function find()
	{
		//到最后一步才去连接数据库，减小类开销
		$this->conn();
		return $this->db->fetch_array($this->_read_sql());
	}
	
	/**
	 * 以array的方式，返回多条查询结果
	 * @return array
	 */
	public function findAll()
	{
		//到最后一步才去连接数据库，减小类开销
		$this->conn();
		
		return $this->db->fetch_arrays($this->_read_sql());
	}

	/**
	 * 以object的方式返回查询结果
	 * @return object
	 */
	public function findObj()
	{
		//到最后一步才去连接数据库，减小类开销
		$this->conn();
		return $this->db->fetch_object($this->_read_sql());
	}

	/**
	 * 以objects的方式返回所有的查询结果
	 * @return object
	 */
	public function findObjs()
	{
		//到最后一步才去连接数据库，减小类开销
		$this->conn();
		return $this->db->fetch_objects($this->_read_sql());
	}

	/**
	 * 用户分页时候，特别有用。返回用户查询的数据，并返回不带limit情况下总数据数。
	 * @return array
	 */
	public function findPage()
	{
		$this->field = 'SQL_CALC_FOUND_ROWS '.$this->field;
		
		$ret_data['data'] = $this->findAll();
		$ret_data['data_count'] =  $this->db->fetch_object('SELECT FOUND_ROWS() count')->count;
		return $ret_data;
	}
	
#------------------------------------------------------------------------------fetch相关操作

	/**
	 * find()的别名，获取一行
	 * @return array
	 */
	public function fetch(){return $this->find();}
	
	/**
	 * findAll()的别名，查询多行数据
	 * @return array
	 */
	public function fetchAll(){return $this->findAll();}

	/**
	 * findObjs()的别名
	 * @return object
	 */
	public function fetchObj(){return $this->findObj();}
	/**
	 * findObjs()的别名
	 * @return object
	 */
	public function fetchObjs(){return $this->findObjs(); }

#------------------------------------------------------------------------------fetch相关操作
	
	
	/**
	 * 获取table_name
	 * @return string $_table_name
	 */
	private function _get_table_name()
	{
		if(! empty($this->table_name))
		{
			$_table_name = $this->table_name;
		}
		else
		{
			//如果是在实例化后使用，则使用当前模型名称
			$current_class = get_class($this);
			if($current_class == 'model')
				throw new ephpException('table_name无法确定！', 6002);
			else
			{
				$_table_name = substr($current_class,0,strlen($current_class) - 5);
				
				//如果设置了表前缀
				if(true == ($tb_prefix = C($this->db_config_name.'.tb_prefix','db') ) ) $_table_name = $tb_prefix.$_table_name;
			}
		}
		return $_table_name;
	}
	
	/**
	 * model进行update更新数据库，如果希望更新所有的数据，
	 * 即不加where条件，则将$f置为true，默认false
	 * @param string $f false 默认，true 执行update不带where子句
	 * @return boolean
	 */
	public function update($f=false)
	{
		$_where = '';
		$_table_name = $this->_get_table_name();
		$_set_string = empty($this->set_string)?'':' SET '.$this->set_string;
		if(empty($this->where) && ($f == false))
			throw new ephpException('警告：执行update操作需要有where子条件，如果你需要无where子句操作，请把使用M()::update(true)', 6003);
		elseif(! empty($this->where))
		{
			$_where = ' WHERE '.$this->where;
		}

		$this->conn();
		$this->db->sql='UPDATE '.$_table_name.$_set_string.$_where;

		//清理使用过的变量
		$this->_clear_var();
		return $this->db->query($this->db->sql);
	}
	/**
	 * model进行delete删除数据库，如果希望删除所有数据
	 * 即不加where条件，则将$f置为true，默认false
	 * @param string $f false 默认，true 执行update不带where子句
	 * @return boolean
	 */
	public function delete($f=false)
	{
		$_where = '';
		$_table_name = $this->_get_table_name();
		if(empty($this->where) && ($f == false))
			throw new ephpException('警告：执行delete操作需要有where子条件，如果你需要无where子句操作，请把使用M()::delete(true)', 6004);
		elseif(! empty($this->where))
		{
			$_where = ' WHERE '.$this->where;
		}
		$this->conn();
		$this->db->sql='DELETE FROM '.$_table_name.$_where;

		//清理使用过的变量
		$this->_clear_var();
		return $this->db->query($this->db->sql);
	}

	/**
	 * model 写入数据库操作，返回插入id
	 * @return integer 最后插入的id
	 */
	public function insert()
	{
		$_table_name = $this->_get_table_name();
		$_set_string = empty($this->set_string)?'':' SET '.$this->set_string;

		$this->conn();
		$this->db->sql='INSERT INTO '.$_table_name.$_set_string;

		//清理使用过的变量
		$this->_clear_var();
		return $this->db->query($this->db->sql);
	}

	/**
	 * insert()的别名
	 * @return void
	 */
	public function add()
	{
		return $this->insert();
	}

	/**
	 * 统计数据条数
	 * 示例:$m->table('test')->select('id')->where('id<12')->count();
	 * @return integer 最后插入的id
	 */
	public function count()
	{
		//$_field = empty($this->field)?'*':$this->field;
		$_table_name = $this->_get_table_name();
		$_where = empty($this->where)?'':' WHERE '.$this->where;

		$this->conn();
		$sql = 'SELECT count('. $this->field .') count FROM '.$_table_name.$_where;
		$this->db->sql = $sql;

		//清理使用过的变量
		$this->_clear_var();
		return $this->db->fetch_object($this->db->sql)->count;
	}

	/**
	 * 清理使用过的变量
	 * @return void
	 */
	private function _clear_var()
	{
		$this->table_name = NULL;
		$this->field = '*';
		$this->orderby = NULL;
		$this->groupby = NULL;
		$this->limit = NULL;
		$this->where = NULL;
		$this->set_string = NULL;
		$this->db_change = NULL;
	}
	/**
	 * 返回影响的数据行数
	 * @return integer
	 */
	public function affected_rows()
	{
		return $this->db->affected_rows();
	}

	/**
	 * 返回刚插入的insert_id
	 * @return integer
	 */
	public function insert_id()
	{
		return $this->db->insert_id();
	}
	
	/**
	 * 查询的表名
	 * @param  String $table_name
	 * @return Object $this
	 */
	public function table($table_name)
	{//trim(get_class($this), 'Model')
		$this->table_name = $table_name;
		return $this;
	}

	/**
	 * table()方法的别名
	 * @param String $table_name
	 */
	public function from($table_name)
	{
		$this->table($table_name);
		return $this;
	}
	
	/**
	 * 指定使用db.config.php哪个数据库配制帐号，例如default、primary
	 * @param unknown_type $db_config_name
	 */
	public function dbconfig($db_config_name)
	{
		// 是否需要重新连接数据了
		if(! empty($this->db_config_name) && ($this->db_config_name != $db_config_name) )
		{
			$this->db_change = true;
		}
		$this->db_config_name = $db_config_name;

		return $this;
	}

	/**
	 * 要查询的数据库字段，SQL中select后的字段名称
	 * @param  String $field
	 * @return Object $this
	 */
	public function field($field)
	{
		$this->field = $field;
		return $this;
	}
	
	/**
	 * SQL中limit的字段，如：0,10
	 * @param  String $limit
	 * @return Object $this
	 */
	public function limit($limit)
	{
		$this->limit = $limit;
		return $this;
	}

	/**
	 * field()的别名
	 * @param string $field select的字段列表
	 * @return object $this
	 */
	public function select($field)
	{
		$this->field($field);
		return $this;
	}
	
	/**
	 * 要写入或更新进数据库的数据。生成sql中的set的部分。
	 * 1、支持直接写string语句，或数组
	 * 2、支持设置不加引号字段，sql中用函数
	 * @param string||array $data 接手字符串或数组
	 * @param string||array $noquote 如果$data是数组，这个字段列出那些字段不用加引号，一个字段为字符串，多个字段该字段必须是一个数组。
	 * @return object
	 */
	public function set($data,$noquote='')
	{
		//如果是string，则直接返回
		if(is_string($data))
		{
			$this->set_string = $data;
			return $this;
		}

		//生成SQL中set的部分，用于数据库更新和删除
		if(is_array($data))
		{
			foreach ($data as $k=>$v)
			{
				// 当noquote是字符串并和noquote相等是不加引号，或者，noquote是数组并且key在noquote中时，不加引号。
				if( (is_string($noquote) && $k != $noquote) || (is_array($noquote) && !in_array($k,$noquote)) )
					$tmp[] = $k."='".$v."'";
				else
					$tmp[] = $k."=".$v;

			}
			$this->set_string = implode(',', $tmp);
		}
		return $this;
	}
	
	/** set()方法的别名。 **/
	public function data($data,$noquote='')
	{
		return $this->set($data,$noquote);
	}
	
	/**
	 * SQL中的where条件
	 * @param  String||array $where sql重点where部分，可以接收一个字符串或数组。
	 * @param  String||array 如果where是数组，这个字段列出那些字段不用加引号，一个字段为字符串，多个字段该字段必须是一个数组。
	 * @return Object $this
	 */
	public function where($where,$noquote='')
	{
		//如果是$where是string，则直接返回
		if(is_string($where))
		{
			$this->where = $where;
			return $this;
		}

		//生成SQL中where的部分
		if(is_array($where))
		{
			foreach ($where as $k=>$v)
			{
				// 当noquote是字符串并和noquote相等是不加引号，或者，noquote是数组并且key在noquote中时，不加引号。
				if( (is_string($noquote) && $k != $noquote) || (is_array($noquote) && !in_array($k,$noquote)) )
					$tmp[] = $k."='".$v."'";
				else
					$tmp[] = $k."=".$v;

			}
			$this->where = implode(' AND ', $tmp);
		}
		return $this;
	}
	
	/**
	 * order by排序
	 * @param  String $orderby
	 * @return Object $this
	 */
	public function orderby($orderby)
	{
		$this->orderby = $orderby;
		return $this;
	}
	
	/**
	 * SQL group by
	 * @param string $groupby 分组
	 * @return object $this
	 */
	public function groupby($groupby)
	{
		$this->groupby = $groupby;
		return $this;
	}
	
	/** 最后执行的sql语句。 **/
	public function getLastSql()
	{
		return $this->db->sql;
	}
}


/* End of file model.class.php */
/* Location: model.class.php */